package org.example.myframework.frame.common.log.aspect;

import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;

// 注入到IOC
@Component
// 用来表示是切面对象
@Aspect
@Slf4j
@ConditionalOnProperty(name = {"log.aspect.enable"}, havingValue = "true",matchIfMissing = true)
public class LogAspect {

    /**
     * 该方法用于找切点
     */
    // 通过pointcut来找到controller中对应添加了注解的地方，即为切入点，并进行捕获
    // @Pointcut("execution(* com.example.service..*(..))") 通过execution来指定扫描指定包路径下的方法。对多个包进行控制时，使用||
     @Pointcut("@annotation(org.example.myframework.frame.common.log.annotation.aop.LogAnnotation)")
    public void logPointCut() {

    }

    /**
     * 做一个环绕通知，将所有的操作都写入在这个方法中。前置、环绕、异常、后置等通知。
     * 通过pointcut找到切点，然后再通过around找到需要在切点执行的方法。
     * @param point 连接点方法，调不同的方法时候的连接点对象是不一样的
     * @return
     */
//    @Around("logPointCut()")
//    public Object around(ProceedingJoinPoint point) throws Throwable{
//        // 输出日志
//        // 获取方法名
//        String methodName = point.getSignature().getName();
//        // 获取注解中的value，通过反射获取
//        // 1.先通过反射获取方法，注解是添加在方法上的
//        MethodSignature signature = (MethodSignature) point.getSignature();
//        Method method = signature.getMethod();
//        // 2.获取方法method上的注解
//        LogAnnotation annotation = method.getAnnotation(LogAnnotation.class);
//
//        log.info("【系统log】：当前操作为" + annotation.value() + "。调用了" + methodName + "方法，返回值是：" + point.proceed());
//        // return的是业务方法的实际返回值，proceed方法（执行接下来的方法）需要处理下异常
//        return point.proceed();
//    }

    /**
     *
     * @param joinPoint
     * @date 2025-05-22
     */
    @Around("logPointCut()")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
        Object[] reqArgs = joinPoint.getArgs();
        // 获取对应的参数
        String reqString = new Gson().toJson(reqArgs);
        // 拿到对应的方法信息（使用了该注解的）
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        // 拿到类名+方法名
        String methodName = methodSignature.getDeclaringType().getName() + "." + methodSignature.getName();
        // 打印入参
        log.info("【系统log】：当前请求方法为{}, 请求参数为:{}", methodName, reqString);
        long startTime = System.currentTimeMillis();
        // 程序业务方法继续执行
        Object respObj = joinPoint.proceed();
        // 获取出参信息
        String respString = new Gson().toJson(respObj);
        long endTime = System.currentTimeMillis();
        log.info("【系统log】：当前请求方法为{}, 返回参数为:{}，总耗时：{}", methodName, respString, endTime - startTime);

    }

}
